package com.xzzz.irda.auth.core.token;


import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.databind.JsonNode;
import com.xzzz.irda.auth.core.authorization.Authorization;
import com.xzzz.irda.auth.core.constants.AuthConstant;
import com.xzzz.irda.auth.core.constants.GrantTypeEnum;
import com.xzzz.irda.auth.core.util.TokenUtil;
import com.xzzz.common.base.util.json.JsonUtil;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.util.List;

/**
 * Redis 存储 授权对象
 *
 * @author wangyf
 * 
 */
public class DefaultAuthorizationRepositoryRedis implements AuthorizationRepository {

    private StringRedisTemplate stringRedisTemplate;

    public DefaultAuthorizationRepositoryRedis(StringRedisTemplate stringRedisTemplate) {
        this.stringRedisTemplate = stringRedisTemplate;
    }


    // region token 信息
    /* ------------------------------< token 信息 >------------------------------
     * 保存在授权主体中, 不单独保存
     * ----------------------------------------------------------------------- */

    @Override
    public AccessToken getAccessToken(String token) {
        return null;
    }

    // endregion


    // region 授权信息Authorization
    /* ------------------------------< 授权信息 >--------------------------------
     * 封装 token 和权限
     * ----------------------------------------------------------------------- */

    /**
     * 保存
     *
     * @param token         授权的 key
     * @param authorization 授权主体
     */
    @Override
    public void saveAuthorization(Authorization authorization) {
        stringRedisTemplate.opsForValue().set(
                TokenUtil.buildTokenKey(authorization),
                JsonUtil.toJson(authorization),
                authorization.getDuration(),
                AuthConstant.Redis.EXPIRE_TIME_UNIT
        );
    }

    /**
     * 获取授权对象
     * redis中保存的时json对象,需要转换为对象返回
     *
     * @param token 授权key
     * @return 授权对象
     */
    @Override
    public Authorization getAuthorization(String token) {
        token = TokenUtil.cutPrefix(token);
        String authJson = stringRedisTemplate.opsForValue().get(TokenUtil.buildTokenKey(token));
        if (StrUtil.isBlank(authJson)) {
            return null;
        }

        JsonNode authObject = JsonUtil.toJsonNode(authJson);
        String grantType = authObject.get(AuthConstant.GRANT_TYPE_PARAM).asText();
        if (StrUtil.isNotBlank(grantType)) {
            Class<? extends Authorization> clazz = GrantTypeEnum.getAuthorizationClass(grantType);
            if (clazz != null) {
                Authorization authorization = JsonUtil.toObj(authJson, clazz);
                if (authorization == null) {
                    return null;
                }
                authorization.setGrantType(grantType);
                authorization.setExpire((authorization.getExpireTime() - System.currentTimeMillis()) / 1000);
                AccessToken accessToken = authorization.getAccessToken();
                accessToken.setExpire(authorization.getExpire());
                authorization.setAccessToken(accessToken);
                return authorization;
            }
        }
        return null;
    }

    /**
     * 刷新授权对象
     *
     * @param token         授权主体 key
     * @param authorization 授权主体
     */
    @Override
    public void refreshAuthorization(Authorization authorization) {
        // 刷新授权信息时,Authorization 的到期倒计时即为有效时长
        authorization.setExpire(authorization.getDuration());
        // 到期时间即为当前时间 + 有效时长
        authorization.setExpireTime(System.currentTimeMillis() + (authorization.getDuration() * 1000));
        // token 信息
        AccessToken accessToken = authorization.getAccessToken();
        // 刷新授权信息时,Token 的到期倒计时即为有效时长
        accessToken.setExpire(authorization.getDuration());
        authorization.setAccessToken(accessToken);
        this.saveAuthorization(authorization);
    }

    /**
     * 删除授权主体
     *
     * @param token 授权主体 key
     */
    @Override
    public void removeAuthorization(String token) {
        token = TokenUtil.cutPrefix(token);
        this.stringRedisTemplate.delete(TokenUtil.buildTokenKey(token));
    }

    // endregion


    // region 权限信息
    /* ------------------------------< 权限信息 >--------------------------------
     * 保存在授权主体中, 不单独保存
     * ----------------------------------------------------------------------- */

    @Override
    public void savePermissions(String key, List<String> permissions) {

    }

    @Override
    public List<String> getPermissions(String key) {
        return null;
    }

    // endregion


    // region token唯一性保证
    /* ------------------------------< token唯一性保证 >--------------------------
     * 是否允许token在任何地方使用
     * ----------------------------------------------------------------------- */

    @Override
    public void saveUniqueToken(Authorization authorization) {
        stringRedisTemplate.opsForValue().set(
                TokenUtil.buildUniqueTokenKey(authorization),
                authorization.getAccessToken().getToken(),
                authorization.getDuration(),
                AuthConstant.Redis.EXPIRE_TIME_UNIT
        );
    }

    @Override
    public String getUniqueToken(String key) {
        return stringRedisTemplate.opsForValue().get(key);
    }

    @Override
    public void removeUniqueToken(String key) {
        stringRedisTemplate.delete(key);
    }

    @Override
    public void refreshUniqueToken(Authorization authorization) {
        this.saveUniqueToken(authorization);
    }

    // endregion
}
